/*****************************************************************************
* File Name: button.c
*
* Version: 1.0
*
* Description:
* This file contains API for reading the button status
*
* Note:
* Defining DISABLE_BUTTON in platform.h to disable button module
* Defining DISABLE_KEYBOARD_INTER_COLUMN_BUTTON in platform.h to disable button between 
* the keyboard rows 
*
* Owner: MRAO
*
* Related Document:
* cy_pins component datasheet
*
* Hardware Dependency:
* Buttons hardware
*
* Code Tested With:
* 1. PSoC Creator 3.1 
* 2. ARM GCC 4.8.4
******************************************************************************
* Copyright (2015), Cypress Semiconductor Corporation.
******************************************************************************
* This software is owned by Cypress Semiconductor Corporation (Cypress) and is
* protected by and subject to worldwide patent protection (United States and
* foreign), United States copyright laws and international treaty provisions.
* Cypress hereby grants to licensee a personal, non-exclusive, non-transferable
* license to copy, use, modify, create derivative works of, and compile the
* Cypress Source Code and derivative works for the sole purpose of creating
* custom software in support of licensee product to be used only in conjunction
* with a Cypress integrated circuit as specified in the applicable agreement.
* Any reproduction, modification, translation, compilation, or representation of
* this software except as specified above is prohibited without the express
* written permission of Cypress.
*
* Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH
* REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 
* Cypress reserves the right to make changes without further notice to the
* materials described herein. Cypress does not assume any liability arising out
* of the application or use of any product or circuit described herein. Cypress
* does not authorize its products for use as critical components in life-support
* systems where a malfunction or failure may reasonably be expected to result in
* significant injury to the user. The inclusion of Cypress' product in a life-
* support systems application implies that the manufacturer assumes all risk of
* such use and in doing so indemnifies Cypress against all charges. Use may be
* limited by and subject to the applicable Cypress software license agreement.
*****************************************************************************/
#include "button.h"

/* Macro used for different states of the motion sensor button */
#define BUTTON_STATE_NONE                   0x0
#define BUTTON_STATE_SINGLE_PRESSED         0x1
#define BUTTON_STATE_SINGLE_RELEASED        0x2
#define BUTTON_STATE_DOUBLE_PRESSED         0x3
#define BUTTON_STATE_DOUBLE_RELEASED        0x4

#ifndef DISABLE_BUTTON
/* To indicate the status of the button (pressed / released) */
static uint8 buttonStatus;

/* Variable to keep track of the device state */
static bool isDeviceActive; 
static bool isFirstTimeDetection;

#if !defined(DISABLE_KEYBOARD) && !defined(DISABLE_KEYBOARD_INTER_COLUMN_BUTTON)
static uint8 buttonState;
static uint32 repeatTimeStamp;
#endif  /* DISABLE_KEYBOARD  || DISABLE_KEYBOARD_INTER_COLUMN_BUTTON */

/*****************************************************************************
* Function Name: Button_Debounce()
******************************************************************************
* Summary:
* This function is used to handle button debouncing effect and correct the button state 
*
* Parameters:
* buttonState - Current button state  
* buttonValue - Debounce value of the button  
*
* Return:
* bool - true it is pressed, false it is not pressed 
*
* Theory:
* Button state will be true if debounce value is more than high threshold and 
* debounce value's 0th bit is one. Button state is false if debounce value
* is less than low threshold and debounce value's 0th bit is zero
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
static bool Button_Debounce(bool buttonState, uint8 *buttonValue)
{
    uint8 debounceValue;
    if(buttonValue != NULL)
    {
        debounceValue = (3*(*buttonValue))/4;
        if(buttonState)
        {
            debounceValue = debounceValue + BUTTON_INCREMENT;
        }
        
        debounceValue |= (*buttonValue & BIT_0_MASK);
        
        if(debounceValue >= BUTTON_SCHMITT_HIGH_THRESH)
        {
            buttonState = true;
            debounceValue |= BIT_0_MASK;
        }
        else if(debounceValue < BUTTON_SCHMITT_LOW_THRESH)
        {
            buttonState = false;
            debounceValue &= (~(uint8)BIT_0_MASK);
        }
        *buttonValue = debounceValue;
    }
    return buttonState;
}

/*****************************************************************************
* Function Name: Button_Init()
******************************************************************************
* Summary:
* This function is used to initialize button module
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* None
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
void Button_Init(void)
{

}

/*****************************************************************************
* Function Name: Button_Poll()
******************************************************************************
* Summary:
* This function is used to poll button status and report the status of the button
*
* Parameters:
* None
*
* Return:
* uint8 - status of the button
*
* Theory:
* Checks and returns the status of the button to the application
*
* Side Effects:
* buttonStatus is updated
* 
* Note:
* None
*****************************************************************************/
uint8 Button_Poll(void)
{
    /* Variable to store the status value that will be used in debounce handling logic */
    static uint8 buttonStatusValue[NUMBER_OF_BUTTONS];
#if !defined(DISABLE_KEYBOARD) && !defined(DISABLE_KEYBOARD_INTER_COLUMN_BUTTON)
    uint8 intermidiateButtonStatus, columnStatus;
#endif /* DISABLE_KEYBOARD  || DISABLE_KEYBOARD_INTER_COLUMN_BUTTON */

    buttonStatus = 0;
    if(isDeviceActive)
    {
        if(Button_Debounce(!(BatteryEn_Voice_Button_Read()),&buttonStatusValue[VOICE_BUTTON_POSITION]))
        {
           buttonStatus |= VOICE_BUTTON_MASK;
        }
    }
    else
    {
        /* Poll the Button in low power mode. Debounce is disabled in low power mode */
        if(Button_Debounce(!(BatteryEn_Voice_Button_Read()),NULL))
        {
           DEVICE_ACTIVITY_DETECTED();
        }
    }

#if !defined(DISABLE_KEYBOARD) && !defined(DISABLE_KEYBOARD_INTER_COLUMN_BUTTON)
    Keyboard_Rows_Write(Keyboard_Rows_MASK>>Keyboard_Rows_SHIFT);
    Keyboard_Columns_Write(Keyboard_Columns_MASK>>Keyboard_Columns_SHIFT);
    CyDelayUs(20);
    Keyboard_Rows_Write(~KEYBOARD_ROWS_SENSOR_POSITION_2);
    CyDelayUs(20);
    columnStatus = (~Keyboard_Columns_Read() & (Keyboard_Columns_MASK>>Keyboard_Columns_SHIFT));  
    Keyboard_Rows_Write(~KEYBOARD_ROWS_SENSOR_POSITION_1);
    CyDelayUs(20);
    intermidiateButtonStatus = (~Keyboard_Columns_Read() & (Keyboard_Columns_MASK>>Keyboard_Columns_SHIFT));  
    
    
    //if(!columnStatus)
    {
        //intermidiateButtonStatus = (~Keyboard_Rows_Read() & KEYBOARD_ROWS_SENSOR_POSITION_1);
        //Debug_Print(DEBUG_MESSAGE_LEVEL_3, "columnStatus = %d,intermidiateButtonStatus = %d\r\n",columnStatus,intermidiateButtonStatus);
        #if 0
        if(intermidiateButtonStatus & RETURN_KEYBOARD_POSITION_MASK)
        {
            buttonStatus |= RETURN_BUTTON_MASK;
            if(isDeviceActive)
            {
                if(!isFirstTimeDetection)
                {
                    repeatTimeStamp = Timer_Get_Time_Stamp();
                    DEVICE_POST_EVENT(BUTTON_EVENT);
                }
                else
                {
                    if(Timer_Time_Elapsed(repeatTimeStamp, BUTTON_REPEAT_TIMEOUT))
                    {
                        repeatTimeStamp = Timer_Get_Time_Stamp();
                        DEVICE_POST_EVENT(BUTTON_EVENT);
                    }
                }
            }
            else
            {
                DEVICE_ACTIVITY_DETECTED();
            }
        }
        else if(isFirstTimeDetection)
        {
            DEVICE_POST_EVENT(BUTTON_EVENT);
        }
        #endif
        if(columnStatus & MOTION_SENSOR_KEYBOARD_POSITION_MASK)
        {
            /* Implements the state machine to detect double click (button press   
             * and release) which is used to trigger motion sensor mode. Third click will 
             * release the motion sensor mode */
            if(!isDeviceActive)
            {
                DEVICE_ACTIVITY_DETECTED();
            }
            if(buttonState == BUTTON_STATE_NONE)
            {
                buttonState = BUTTON_STATE_SINGLE_PRESSED;
            }
            else if(buttonState == BUTTON_STATE_SINGLE_RELEASED)
            {
                buttonState = BUTTON_STATE_DOUBLE_PRESSED;
            }
        }    
        else
        {
            if(buttonState == BUTTON_STATE_SINGLE_PRESSED)
            {
                buttonState = BUTTON_STATE_SINGLE_RELEASED;
            }
            else if(buttonState == BUTTON_STATE_DOUBLE_PRESSED)
            {
                buttonState = BUTTON_STATE_NONE;
            }
        }
        if(buttonState == BUTTON_STATE_SINGLE_RELEASED)
        {
            buttonStatus |= MOTION_SENSOR_BUTTON_MASK;
        }
        else
        {
            buttonStatus &= ~MOTION_SENSOR_BUTTON_MASK;
        }
#ifndef DISABLE_AUDIO
        if(intermidiateButtonStatus & VOICE_SENSOR_KEYBOARD_POSITION_MASK)
        {
    				if(!isDeviceActive)
    					{
    						DEVICE_ACTIVITY_DETECTED();
    						Debug_Print(DEBUG_MESSAGE_LEVEL_3,"voice activeing\r\n");
    					}
    				else
    					{
                buttonStatus |= VOICE_BUTTON_MASK;						
    					}          
        }
        else
        {
          buttonStatus &= ~VOICE_BUTTON_MASK;
        }
#endif        
    }
    Keyboard_Columns_Write(Keyboard_Columns_MASK>>Keyboard_Columns_SHIFT);
    Keyboard_Rows_Write(~((uint8)Keyboard_Rows_MASK>>Keyboard_Rows_SHIFT));    
#endif /* DISABLE_KEYBOARD  && DISABLE_KEYBOARD_INTER_COLUMN_BUTTON */
    return buttonStatus;
}
    
/*****************************************************************************
* Function Name: Button_Set_State()
******************************************************************************
* Summary:
* This function is used to set the device state and make corresponding configuration
* changes in button module
*
* Parameters:
* state - state of the device
*
* Return:
* None
*
* Theory:
* Set the isDeviceActive variable which is used in Button_Poll api
*
* Side Effects:
* isDeviceActive is updated
* 
* Note:
* None
*****************************************************************************/
void Button_Set_State(Device_State state)
{
    if(state == DEVICE_ACTIVE)
    {
        isDeviceActive = true;
    }
    else
    {
        isDeviceActive = false;
    }
}

/*****************************************************************************
* Function Name: Button_Get_Report()
******************************************************************************
* Summary:
* This function is used to update report with respect to the button status
*
* Parameters:
* report - structure to be filled
*
* Return:
* ReportType - type of the report 
*
* Theory:
* Fills the report structure with the button status
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
ReportType Button_Get_Report(Report *report)
{
    ReportType reportType = NO_REPORT;
    if(DEVICE_GET_EVENT(BUTTON_EVENT))
    {
        if(buttonStatus & RETURN_BUTTON_MASK)
        {
            report->keyboard_report.keycode[report->keyboard_report.keylength_used++] = RETURN_KEY_CODE;
            report->ir_report.command = RETURN_IR_KEY_CODE;
            report->ir_report.isRepeatCode = isFirstTimeDetection;
            isFirstTimeDetection = true;
            reportType |= KEYBOARD_REPORT;
        }
        else if(isFirstTimeDetection)
        {
            isFirstTimeDetection = false;
            reportType |= KEYBOARD_REPORT;
        }
    }
    return reportType;
}

/*****************************************************************************
* Function Name: Button_IsActive()
******************************************************************************
* Summary:
* This function is used to check if any of the button is still pressed
*
* Parameters:
* None
*
* Return:
* bool - true if any button is pressed
*
* Theory:
* Checks if any button is pressed or not
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
bool Button_IsActive(void)
{
    bool result = false;
    if(buttonStatus & (VOICE_BUTTON_POSITION | RETURN_BUTTON_MASK))
    {
        result = true;
    }
    return result;
}

/*****************************************************************************
* Function Name: Button_Stop()
******************************************************************************
* Summary:
* This function stops the button module
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* Stops the button module by disabling the interrupt and by setting the drive mode 
* BatteryEn_Voice_Button to High Impedance Digital
*
* Side Effects:
* None
* 
* Note:
* None
*****************************************************************************/
void Button_Stop(void)
{
    BatteryEn_Voice_Button_SetDriveMode(BatteryEn_Voice_Button_DM_DIG_HIZ);
}

#endif /* DISABLE_BUTTON */
